#!/usr/bin/env python
# -*- coding: utf-8 -*-

from IL.Socket.Singleton import singleton
import Market
import threading
import PreMktContainer

@singleton
class Memory:
    def __init__(self):
        self.market_source = Market.MarketSource()
        self.premkt = PreMktContainer.Memory()
        self.basket_data = dict()
        self.fail_order = set()
        self.success_order = set()
        self.order_RidToInfo = dict()
        self.order_seqToInfo = dict()
        self.order_search = {
            u'all': set(),
            u'variety': {
                u'stock': set(),
                u'other': set()
            },
            u'code': dict(),
            u'ip': dict()
        }
        self.products = dict()
        self.login_result = str()
        self.position_stocks = dict()
        self.total_cash = dict()
        self.money = dict()
        self.basketUnfinished_SIDToInfo = dict()
        self.trades_orderIDToInfo = dict()
        self.trades_search = {
            u'all': set(),
            u'variety': {
                u'stock': set(),
                u'ETF': set(),
                u'reverse': set(),
                u'other': set()
            },
            u'market': {
                u'SH': set(),
                u'SZ': set()
            },
            u'trade_type': {
                u'common': set(),
                u'cancel': set(),
                u'waste': set()
            },
            u'order_type': {
                u'stock': set(),
                u'etf': set(),
                u'etf_PAR': set(),
                u'reverse': set(),
                u'other': set()
            },
            u'terminal': dict(),
            u'policyID': dict(),
            u'real_ip': dict(),
            u'stock_code': dict(),
            u'etf_code': dict()
        }
        self.basketStrategyInfo = dict()
        self.ETF_strategyIDtoRequestID = dict()
        self.locks = {
            'Trade': threading.RLock()
        }
        self.update_basketInfo = dict()
        self.policy_result = dict()
        self.sub_etf_info_data = dict()
        self.etfinfo = dict()

    def CalcBasketTrade(self, policyid, price):
        if not self.basket_data.get(policyid, False):
            self.basket_data[policyid] = [0, 0]
        self.basket_data[policyid][0] += price
        if not self.ETF_strategyIDtoRequestID.get(policyid, False):
            self.basket_data[policyid][1] /= 1
        else:
            self.basket_data[policyid][1] /= self.basketStrategyInfo[self.ETF_strategyIDtoRequestID[trade.policyid]]['ygCost']

    def add_orderSeq(self, order, requestID):
        if not order.ret_code:
            self.success_order.add(order.order_no)
        else:
            self.fail_order.add(order.order_no)
        self.order_RidToInfo[requestID] = order

    def add_orderInfo_SS(self, order):
        for i in order.stock_order:
            self.order_seqToInfo[i.order_no] = i
            try:
                if self.market_source.getCodeInfo(i.stock_id).type == 0x10:
                    self.order_search['variety']['stock'].add(i.order_no)
                else:
                    self.order_search['variety']['other'].add(i.order_no)
            except:
                self.order_search['variety']['stock'].add(i.order_no)

            self.dict_tools_add(self.order_search, 'code', i.stock_id, i.order_no)
            self.dict_tools_add(self.order_search, 'ip', i.trader_ip, i.order_no)
            self.order_search['all'].add(i.order_no)

    def add_orderInfo(self, order):
        for i in order.orders:
            if i.orderseq not in self.success_order:
                print u"为什么没有在正确的集合订单容器中!"
            self.order_seqToInfo[i.orderseq] = i

            try:
                if self.market_source.getCodeInfo(i.code).type == 0x10:
                    self.order_search['variety']['stock'].add(i.orderseq)
                else:
                    self.order_search['variety']['other'].add(i.orderseq)
            except:
                self.order_search['variety']['stock'].add(i.orderseq)

            self.dict_tools_add(self.order_search, 'code', i.code, i.orderseq)
            self.dict_tools_add(self.order_search, 'ip', i.ip, i.orderseq)
            self.order_search['all'].add(i.orderseq)

    def add_LoginInfo(self, login):
        self.login_result = login.result

    def add_TotalCash(self, cash):
        self.total_cash['stock'] = cash.stock
        self.total_cash['future'] = cash.future
        self.total_cash['buyFreeze'] = cash.buyfreeze
        self.total_cash['sellFreeze'] = cash.sellfreeze
        self.total_cash['shStock'] = cash.shstock
        self.total_cash['szStock'] = cash.szstock
        self.total_cash['IF'] = cash.if_count
        self.total_cash['IH'] = cash.ih_count
        self.total_cash['IC'] = cash.ic_count
        self.total_cash['stock'] = cash.stock
        self.total_cash['total_money'] = cash.total_money

    def add_Position_SS(self, position):
        for i in position.stock_position:
            self.position_stocks[i.stock_id] = i

    def add_Position(self, position):
        for i in position.positions:
            self.position_stocks[i.code] = i

    def add_Money(self, money):
        self.money['total'] = money.total
        self.money['usable'] = money.use
        self.money['freeze'] = money.nouse

    def add_Money_SS_Sub(self, money):
        self.money['total'] = money.asset
        self.money['usable'] = money.capital_avaliable
        self.money['freeze'] = money.capital_freezed_by_buy + money.capital_freezed_by_others
        self.money['balance'] = money.capital_balance
        self.money['freeze_buy'] = money.capital_freezed_by_buy
        self.money['freeze_sell'] = money.capital_freezed_by_others
        self.money['market_value'] = money.market_value

    def add_Money_SS(self, money):
        self.money['total'] = money.stock_asset.asset
        self.money['usable'] = money.stock_asset.capital_avaliable
        self.money['freeze'] = money.stock_asset.capital_freezed_by_buy + money.stock_asset.capital_freezed_by_others
        self.money['balance'] = money.stock_asset.capital_balance
        self.money['freeze_buy'] = money.stock_asset.capital_freezed_by_buy
        self.money['freeze_sell'] = money.stock_asset.capital_freezed_by_others
        self.money['market_value'] = money.stock_asset.market_value


    def add_TradeDetail_SS(self, trade):
        self.locks['Trade'].acquire()
        for i in trade.stock_knock:
            self.trades_search['all'].add(i.order_no)
            if not self.trades_orderIDToInfo.get(i.order_no, None):
                self.trades_orderIDToInfo[i.order_no] = dict()
            sumVolume = self.trades_orderIDToInfo[i.order_no].get('sumVolume', 0)
            avgPrice = self.trades_orderIDToInfo[i.order_no].get('avgPrice', 0)
            tradeCount = self.trades_orderIDToInfo[i.order_no].get('tradeCount', 1)
            if tradeCount > 1:
                avgPrice = (avgPrice * tradeCount + i.match_price / 10000) / (tradeCount+1)
                tradeCount += 1
            else:
                avgPrice = i.match_price / 10000
            self.trades_orderIDToInfo[i.order_no] = {
                u'code': i.stock_id,
                u'name': i.stock_name,
                u'time': i.match_time,
                u'volume': i.match_volume,
                u'price': i.match_price / 10000,
                u'sumVolume': i.match_volume + sumVolume,
                u'avgPrice': avgPrice,
                u'total': i.match_amount / 10000,
                u'order_volume': i.order_volume,
                u'order_price': i.order_price,
                u'bs_flag': i.bs_flag,
                u'trade_type': i.match_type,
                u'trade_no': i.match_no,
                u'order_no': i.order_no,
                u'no': i.batch_no,  # 所属合同号，先随便填写一个
                u'etf': i.belonged_etf_code,
                u'ip': i.trader_id,
                u'real_ip': i.trader_ip,
                u'policy_id': i.policy_id,
                u'create_time': i.create_time,
                u'match_time': i.match_time,
                u'tradeCount': tradeCount
            }

            if i.belonged_etf_code:
                self.trades_search['variety']['other'].add(i.order_no)
                self.dict_tools_add(self.trades_search, 'etf_code', i.belonged_etf_code, i.order_no)
            else:
                self.trades_search['variety']['stock'].add(i.order_no)

            if i.market:
                self.trades_search['market']['SH'].add(i.order_no)
            else:
                self.trades_search['market']['SZ'].add(i.order_no)

            if i.match_type > 0:
                self.trades_search['trade_type']['waste'].add(i.order_no)
            elif i.match_type == 2:
                self.trades_search['trade_type']['cancel'].add(i.order_no)
            else:
                self.trades_search['trade_type']['common'].add(i.order_no)

            ret = self.premkt.get_IsETF(i.stock_id)
            if ret and (i.order_bs_flag == 0 or i.order_bs_flag == 1):
                self.trades_search['order_type']['etf'].add(i.order_no)
            elif ret and (i.order_bs_flag == 2 or i.order_bs_flag == 3):
                self.trades_search['order_type']['etf_PAR'].add(i.order_no)
            elif not ret:
                self.trades_search['order_type']['stock'].add(i.order_no)
            else:
                self.trades_search['order_type']['other'].add(i.order_no)

            self.dict_tools_add(self.trades_search, 'terminal', i.trader_id, i.order_no)
            self.dict_tools_add(self.trades_search, 'policyID', i.policy_id, i.order_no)
            self.dict_tools_add(self.trades_search, 'real_ip', i.trader_ip, i.order_no)
            self.dict_tools_add(self.trades_search, 'stock_code', i.stock_id, i.order_no)
        self.locks['Trade'].release()

    def add_TradeDetail(self, trade):
        self.locks['Trade'].acquire()
        for i in trade.trades:
            self.trades_orderIDToInfo[i.tradeid] = i

            self.trades_search['all'].add(i.tradeid)

            if i.ordertype == 1:
                self.trades_search['variety']['ETF'].add(i.tradeid)
            elif i.ordertype == 2:
                self.trades_search['variety']['reverse'].add(i.tradeid)
            elif i.ordertype == 3:
                self.trades_search['variety']['other'].add(i.tradeid)
            else:
                self.trades_search['variety']['stock'].add(i.tradeid)

            if i.market:
                self.trades_search['market']['SZ'].add(i.tradeid)
            else:
                self.trades_search['market']['SH'].add(i.tradeid)

            if i.tradetype == 2:
                self.trades_search['type']['waste'].add(i.tradeid)
            elif i.tradetype == 1:
                self.trades_search['type']['cancel'].add(i.tradeid)
            else:
                self.trades_search['type']['common'].add(i.tradeid)

            self.dict_tools_add(self.trades_search, 'terminal', i.ip, i.tradeid)
            self.dict_tools_add(self.trades_search, 'policyID', i.policyid, i.tradeid)
            self.dict_tools_add(self.trades_search, 'real_ip', i.realip, i.tradeid)
            self.dict_tools_add(self.trades_search, 'stock_code', i.code, i.tradeid)
            self.dict_tools_add(self.trades_search, 'etf_code', i.etf, i.tradeid)

            self.CalcBasketTrade(i.policyid, i.price)
        self.locks['Trade'].release()

    def dict_tools_add(self, myDict, feild, key, id):
        if myDict[feild].get(key, None):
            myDict[feild][key].add(id)
        else:
            myDict[feild][key] = set()
            myDict[feild][key].add(id)

    def add_BasketUnfinished(self, basket):
        for i in basket.baskets:
            self.basketUnfinished_SIDToInfo[i.policyid] = i

    def add_BasketPolicy(self, basket, requestID):
        if not self.basketStrategyInfo.get(requestID, False):
            self.basketStrategyInfo[requestID] = dict()
        self.basketStrategyInfo[requestID]['position_rate'] = basket.rate
        self.basketStrategyInfo[requestID]['kshCount'] = basket.ksh_count
        self.basketStrategyInfo[requestID]['ygCost'] = basket.yg_cost
        self.basketStrategyInfo[requestID]['policyID'] = basket.policyid
        self.ETF_strategyIDtoRequestID[basket.policyid] = requestID

    def get_BasketPolicy(self, requestID):
        return self.basketStrategyInfo[requestID]

    def get_BasketTradeInfo(self, policyID):
        return self.basket_data[policyID]

    def get_CompleteTradeDetail(self, variety=None, market=None, policyID=[], idAdress=[], terminal=[],
                                ot_stock=None, ot_etf_trade=None, ot_etf=None, ot_reverse=None, ot_other=None,
                                tt_common=None, tt_cancel=None, tt_waste=None, stockCode=[], etfCode=[]):
        self.locks['Trade'].acquire()
        search_id = self.trades_search['all']
        if variety:
            if variety == 'other':
                search_id = search_id - self.trades_search['variety']['stock']
            else:
                search_id = search_id & self.trades_search['variety'][variety]
        if market:
            search_id = search_id & self.trades_search['market'][market]

        if ot_stock:
            search_id = search_id & self.trades_search['order_type']['stock']
        if ot_etf_trade:
            search_id = search_id & self.trades_search['order_type']['etf']
        if ot_etf:
            search_id = search_id & self.trades_search['order_type']['etf_PAR']
        # if ot_reverse:
        #     search_id = search_id & self.trades_search['order_type']['reverse']
        if ot_other:
            search_id = search_id & self.trades_search['order_type']['other']

        if tt_common:
            search_id = search_id & self.trades_search['trade_type']['common']
        if tt_cancel:
            search_id = search_id & self.trades_search['trade_type']['cancel']
        if tt_waste:
            search_id = search_id & self.trades_search['trade_type']['waste']

        if stockCode:
            search_id = search_id & self.trades_search['stock_code'][stockCode]
        if etfCode:
            search_id = search_id & self.trades_search['etf_code'][etfCode]
        if policyID:
            search_id = search_id & self.trades_search['policyID'][policyID]
        if idAdress:
            search_id = search_id & self.trades_search['real_ip'][idAdress]
        if terminal:
            search_id = search_id & self.trades_search['terminal'][terminal]

        ret_list = list()
        for i in search_id:
            ret_list.append(self.trades_orderIDToInfo[i])

        self.locks['Trade'].release()
        return ret_list

    def get_EasyTradeDetail(self, variety=None, terminal=None):
        self.locks['Trade'].acquire()
        search_id = self.trades_search['all']
        if variety:
            if variety == 'other':
                search_id = search_id - self.trades_search['variety']['stock']
            else:
                search_id = search_id & self.trades_search['variety'][variety]
        if terminal:
            search_id = search_id & self.trades_search['terminal'][terminal]
        ret_list = list()
        for i in search_id:
            ret_list.append(self.trades_orderIDToInfo[i])
        self.locks['Trade'].release()
        return ret_list

    def get_OrderList(self, variety=None, code=None, ip=None):
        try:
            search_id = set()
            if variety:
                search_id = search_id | self.order_search['variety'][variety]
            else:
                search_id = search_id | self.order_search['all']

            if ip:
                search_id = search_id & self.order_search['ip'][ip]
            ret_list = list()
            for i in search_id:
                ret_list.append(self.order_seqToInfo[i])

            filterRetList = list()
            if code:
                for item in ret_list:
                    for i in code:
                        if item.stock_id.find(i) != -1:
                            filterRetList.append(item)
            else:
                filterRetList = ret_list
            return filterRetList
        except:
            return list()

    def get_OrderList_Code(self, code):
        try:
            search_id = self.order_search['code'][code]
            ret_list = list()
            for i in search_id:
                ret_list.append(self.order_seqToInfo[i])
            return ret_list
        except:
            return list()

    def get_TotalCash(self):
        
        ret = self.total_cash
        return ret

    def get_Money(self):
        
        ret = self.money
        return ret

    def get_BasketUnfinished(self):
        ret = self.basketUnfinished_SIDToInfo.values()
        return ret

    def get_Position(self):
        ret = self.position_stocks.values()
        return ret

    def get_Position_code(self, code):
        ret = self.position_stocks.get(code, None)
        return ret

    def get_Login(self):

        ret = self.login_result
        return ret

    def get_orderSeq(self, requestID):
        try:
            ret = self.order_RidToInfo[requestID]
            return ret
        except:
            return None

    def get_orderInfo(self, orderSeq):
        try:
            ret = self.order_seqToInfo[orderSeq]
            return ret
        except:
            return None

    def update_BasketInfo(self, msg):
        if self.update_basketInfo.get(msg.policy_id, None) is None:
            self.update_basketInfo[msg.policy_id] = dict()
        self.update_basketInfo[msg.policy_id] = {
            'rate': msg.rate,
            'ksh_count': msg.ksh_count,
            'yg_cost': msg.yg_cost,
            'finished_asset': msg.finished_asset,
            'finished_iopv': msg.finished_iopv
        }

    def add_PolicyResult(self, msg):
        if self.policy_result.get(msg.policy_id, None) is None:
            self.policy_result[msg.policy_id] = dict()
        self.policy_result[msg.policy_id] = msg.ret_code

    def add_sub_key_etf_info(self, msg):
        if self.sub_etf_info_data.get(msg.code, None) is None and msg.ret_code == 0:
            self.sub_etf_info_data[msg.code] = dict()

    def update_EtfInfo(self, msg, field):
        if self.etfinfo.get(msg.code, None) is None:
            self.etfinfo[msg.code] = dict()
        if field == 'LimitUp':
            self.etfinfo[msg.code]['LimitUp'] = msg.value
        elif field == 'LimitDow':
            self.etfinfo[msg.code]['LimitDow'] = msg.value
        elif field == 'Stop':
            self.etfinfo[msg.code]['Stop'] = msg.value
        elif field == 'MaxPrice':
            self.etfinfo[msg.code]['MaxPrice'] = msg.value
        elif field == 'MinPrice':
            self.etfinfo[msg.code]['MinPrice'] = msg.value
        elif field == 'DIOPVB1':
            self.etfinfo[msg.code]['DIOPVB1'] = msg.value
        elif field == 'DIOPVS1':
            self.etfinfo[msg.code]['DIOPVS1'] = msg.value
        elif field == 'Basis_B1':
            self.etfinfo[msg.code]['Basis_B1'] = msg.value
        elif field == 'Basis_S1':
            self.etfinfo[msg.code]['Basis_S1'] = msg.value
        elif field == 'Basis_Open':
            self.etfinfo[msg.code]['Basis_Open'] = msg.value
        elif field == 'Basis_Close':
            self.etfinfo[msg.code]['Basis_Close'] = msg.value

    def get_EtfInfo(self, code, field):
        if self.etfinfo.get(code, None) is None:
            return 0
        try:
            return self.etfinfo[code][field]
        except:
            return 0

    def get_Trade_order_no(self, order_no):
        return self.trades_orderIDToInfo[order_no]

    def get_Order_order_no(self, order_no):
        return self.order_seqToInfo[order_no]